//
//  StatusSettingsController.m
//  Statz
//
//  Created by dmaclach on 6/19/07.
//
// Copyright 2007 Google Inc.
// 
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License.  You may obtain a copy
// of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
// License for the specific language governing permissions and limitations under
// the License.
//

#import <Carbon/Carbon.h>
#import "StatusSettingsController.h"
#import "AppDelegate.h"
#import "StatzSink.h"
#import "Status.h"
#import "DelegatingTableColumn.h"
#import "AccountSettingsWindowController.h"
#import "CustomCellSizeTableView.h"
#import "StatusSettingsTitleItem.h"
#import "StatzPlugin.h"
#import "UserStatusSource.h"
#import "NSTableView+Statz.h"
#import "StatusSettingsArrayController.h"

static NSString *const kStatusSettingsNibName = @"StatusSettings";

@interface StatusSettingsController (StatusSettingsControllerPrivate)
- (void)editSelectedStatusIfAppropriateAtTime:(NSTimer*)sender;
@end

#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
@interface NSTableView (AdditionsFor10_5)
- (void)setSelectionHighlightStyle:(int)selectionHighlightStyle;
@end

@interface NSWindow (AdditionsFor10_5)
- (void)setContentBorderThickness:(float)borderThickness forEdge:(NSRectEdge)edge;
@end

#endif

#define NormalSegmentedCellStyle 1
#define FlatSegmentedCellStyle 2
@interface NSSegmentedCell (Private)
- (void)_setSegmentedCellStyle:(int)style;
@end

@interface NSSegmentedControl (AdditionsFor10_5)
- (void)setSegmentStyle:(int)style;
@end



@implementation StatusSettingsController

- (id)initWithDelegate:(AppDelegate *)inDelegate  {
  if ((self = [super initWithWindowNibName:kStatusSettingsNibName])) {
    delegate_ = inDelegate;
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(statzStateChanged:)
                                                 name:StatzStateChangedNotification
                                               object:nil];
  }
  return self;
}

- (void)dealloc {
  [[NSNotificationCenter defaultCenter] removeObserver:self];
  [super dealloc];
}

- (int)numberOfRowsInTableView:(NSTableView *)tableView {
  return [[sourcesController_ arrangedObjects] count];
}

- (BOOL)isLeopard {
  SInt32 MacVersion = 0;
  if (Gestalt(gestaltSystemVersion, &MacVersion) != noErr) return NO;
  return MacVersion >= 0x1050;
}

- (void)windowDidLoad {
  [super windowDidLoad];
  windowLoaded_ = YES;
  
  [[self window] setOpaque:NO];
  
  BOOL isLeopard = [self isLeopard];
  [[self window] setBackgroundColor:[NSColor colorWithDeviceWhite:1.0f 
                                                            alpha:isLeopard ? 0.85f : 0.95f]];
														 
  [[sourceTable_ enclosingScrollView] setDrawsBackground:NO];
  [[statusTable_ enclosingScrollView] setDrawsBackground:NO];
  
  [statusTable_ setIntercellSpacing:NSMakeSize(0.0f, 8.0f)];
  
  [sourceTable_ selectRow:1 byExtendingSelection:NO];
  [sourceTable_ setIntercellSpacing:NSMakeSize(3.0f, 2.0f)];
  
  if ([NSSegmentedCell instancesRespondToSelector:@selector(setSegmentStyle:)]) {
    [addRemoveControl_ setSegmentStyle:FlatSegmentedCellStyle];
    [gearControl_ setSegmentStyle:FlatSegmentedCellStyle];
    
    
    [statusTable_ setBackgroundColor:[NSColor clearColor]];
  } else {
    // Setup cells on Tiger
    [addRemoveControl_  setImage:[NSImage imageNamed:@"Add"] forSegment:0];
    [addRemoveControl_  setImage:[NSImage imageNamed:@"Remove"] forSegment:1];
      
    [gearControl_  setImage:[NSImage imageNamed:@"Action"] forSegment:0];
    [gearControl_ setLabel:nil forSegment:0];
    
    [statusTable_ setBackgroundColor:[[self window] backgroundColor]];
 }
  
  
  if ([NSTableView instancesRespondToSelector:
       @selector(setSelectionHighlightStyle:)])
    [sourceTable_ setSelectionHighlightStyle:1];
  
  NSSize size = [sourceTable_ intercellSpacing];
  size.height += 4;
  [sourceTable_ setIntercellSpacing:size];
  [self setWindowFrameAutosaveName:kStatusSettingsNibName];
  if (![[self window] setFrameUsingName:kStatusSettingsNibName]) {
    [[self window] center];
  }
  [[variablesPopup_ menu] setDelegate:self];
  
  [gearControl_ setMenu:gearMenu_ forSegment:0];
  [addRemoveControl_ setAction:@selector(addRemoveStatus:)];
  [addRemoveControl_ setTarget:self];
  
  if ([[self window] respondsToSelector:@selector(setContentBorderThickness:forEdge:)]) {
    [[self window] setContentBorderThickness:24 forEdge:NSMinYEdge];
  }
  [accountSettings_ addObserver:self forKeyPath:@"hidden" options:NSKeyValueObservingOptionNew context:nil];
  NSArray *sources = [sourcesController_ arrangedObjects];
  StatzSource *source = [sources objectAtIndex:1];
  [statusTable_ selectRow:[source currentStatusIndex] byExtendingSelection:NO];
  
  // About stuff
  NSBundle *mainBundle = [NSBundle mainBundle];
  [appName_ setStringValue:[mainBundle objectForInfoDictionaryKey:@"CFBundleName"]];
  [appVersion_ setStringValue:[mainBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]];
  [appCopyright_ setStringValue:[mainBundle objectForInfoDictionaryKey:@"NSHumanReadableCopyright"]];
  
  [[[self window] contentView] addSubview:aboutView_];
  [aboutView_ setFrameOrigin:NSMakePoint(178, 32)];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
  if([[change objectForKey:NSKeyValueChangeKindKey] intValue] == NSKeyValueChangeSetting) {
    NSView *scrollView = [[statusTable_ superview] superview];
    NSRect frame = [scrollView frame];
    float height = NSHeight([accountSettings_ bounds]);
    if(![[change objectForKey:NSKeyValueChangeNewKey] intValue]) {
      height *= -1.0f;
    }
    frame.size.height += height;
    frame.origin.y -= height;
    [scrollView setFrame:frame];
  }
}

- (IBAction)addSource:(id)sender {
  [sourcesController_ add:sender];  
}

- (IBAction)removeSource:(id)sender {
  NSArray *sources = [sourcesController_ selectedObjects];
  if ([sources count] == 1) {
    id source = [sources objectAtIndex:0];
    
    if ([source isKindOfClass:[StatzSink class]]) {
      [source setEnabled:NO];
      [sourcesController_ rearrangeObjects];
    } else {
      [sourcesController_ remove:sender];
    }
  } else {
    NSLog(@"Unexpected count of selected sources %@", sources);
  }
}

- (IBAction)addAccount:(id)sender {
  id obj = [sender representedObject];
  [obj setEnabled:YES];
  [sourcesController_ rearrangeObjects];
  [sourcesController_ setSelectedObjects:[NSArray arrayWithObject:obj]];
  [[statusTable_ window] makeFirstResponder:statusTable_];
  id plugin = [obj plugin];
  if ([plugin hasPreferences]) {
    BOOL badUsername = [[plugin username] length] == 0;
    BOOL badPassword = [[plugin password] length] == 0;
    if (badUsername || badPassword) {
      [self setShowAccountSettings:YES];
      NSResponder *responder = badUsername ? username_ : password_;
      [[self window] makeFirstResponder:responder];
    }
  }
}
  
- (IBAction)addRemoveStatus:(id)sender {
  if ([sender selectedSegment] == 0) {
    int editedRow = [statusTable_ editedRow];
    if (editedRow != -1) {
      [statusTable_ deselectRow:editedRow];
    }
    Status *newStatus = [[[Status alloc] init] autorelease];
    [statusesController_ addObject:newStatus]; 
    statusToEdit_ = newStatus;
    [NSTimer scheduledTimerWithTimeInterval:0.1 
                                     target:self
                                   selector:@selector(editSelectedStatusIfAppropriateAtTime:) 
                                   userInfo:nil 
                                    repeats:NO];
  } else {
    [statusesController_ remove:sender];
  }
}

- (IBAction)showWindow:(id)sender {
  
  [sourcesController_ rearrangeObjects];
  
  NSRect screenRect = [[NSScreen mainScreen] frame];
  NSRect visibleScreenRect = [[NSScreen mainScreen] visibleFrame];
  NSWindow *window = [self window];
  NSPoint leftOfItem = [delegate_ leftOfStatusItem];
  float screenX = NSMaxX(screenRect) - NSWidth([window frame]) - 10;
  float itemX = leftOfItem.x - NSWidth([[sourceTable_ enclosingScrollView] bounds]);
  float xOrigin = MIN(screenX, itemX);
  NSPoint origin = 
    NSMakePoint(xOrigin,
                NSMaxY(visibleScreenRect) - NSHeight([window frame]));
  [window setFrameOrigin:origin];
  [super showWindow:sender];
  [window setAlphaValue:1.0f];
}

- (void)windowDidResignKey:(NSNotification *)notification {
  [self hideAbout:nil];
  [self close];  
}

- (void)tableView:(NSTableView *)tableView 
  willDisplayCell:(id)cell
   forTableColumn:(NSTableColumn *)tableColumn 
              row:(int)row {
  if ([tableView isEqualTo:sourceTable_]) {
    if ([[tableColumn identifier] isEqualToString:@"name"]) {
      NSArray *sources = [sourcesController_ arrangedObjects];
      StatzSource *source = [sources objectAtIndex:row];
      [cell setObjectValue:[source displayNameAndStatus]];
    }
  }
}

- (float)tableView:(NSTableView *)tableView heightOfRow:(int)row {
  float height = [tableView rowHeight];
  if ([tableView isEqualTo:sourceTable_]) {
    NSArray *sources = [sourcesController_ arrangedObjects];
    id item = [sources objectAtIndex:row];
    if ([item isKindOfClass:[StatusSettingsTitleItem class]]) {
      NSAttributedString *name = [(StatusSettingsTitleItem*)item name];

      if ([[name string] isEqualToString:@""]) {
        height = 4.0f;
      } else {
        height = 16.0f;
      }
    } 
  }
  return height;
}

- (BOOL)tableView:(NSTableView*)tableview 
          drawRow:(int)row 
          rowRect:(NSRect)rowRect 
         clipRect:(NSRect)clipRect {
  BOOL handled = NO;
  if ([tableview isEqualTo:sourceTable_]) {
    NSArray *sources = [sourcesController_ arrangedObjects];
    id item = [sources objectAtIndex:row];
    if ([item isKindOfClass:[StatusSettingsTitleItem class]]) {
      handled = YES;
      NSAttributedString *name = [(StatusSettingsTitleItem*)item name];
      rowRect.origin.x += 10;
      rowRect.size.width -= 10;
      // Move the string down to be vertically centered 
      // TODO: calculate this based on ascender height (since it is all caps)
      rowRect.origin.y += 5.0f;
      rowRect.size.height = [name size].height;
      [name drawInRect:rowRect];
      
      if (item == [sourcesController_ accountsTitleItem]) {
        StatzState state = kStatzStateNone;
        NSEnumerator *sourceEnum = [[sourcesController_ arrangedObjects] objectEnumerator];
        StatzSink *sink;
        unsigned int mask = UINT_MAX; 
        while ((sink = [sourceEnum nextObject])) {
          if ([sink isKindOfClass:[StatzSink class]]) {
            StatzState sinkState = [sink state];
            if (state == kStatzStateNone) {
              state = sinkState;
            } else if (state != sinkState && sinkState != kStatzStateNone) {
              state = kStatzStateMixed;
            }
            unsigned int sinkMask = [[sink plugin] stateMenuMask];
            if (sinkMask != kStatzStateNone) {
              mask &= sinkMask;
            }
          }
        }
        if (state == kStatzStateMixed) {
          mask |= kStatzStateMixed;
        }
        NSMenu *menu = [StatzSink stateMenuWithStates:mask target:self];
        [menu setDelegate:self];
        [masterStatePopup_ setMenu:menu];
        NSRect newRect = [[masterStatePopup_ superview] convertRect:rowRect fromView:tableview];
        newRect.origin.y -= 4;
        newRect.origin.x = NSMaxX(newRect) - ([masterStatePopup_ bounds].size.width);
        [masterStatePopup_ setFrameOrigin:newRect.origin];
        [masterStatePopup_ selectItemWithTag:state];
        [masterStatePopup_ setEnabled:mask != UINT_MAX];
      }
    }
  }
  return handled;
}

- (BOOL)tableView:(NSTableView *)tableView 
              shouldEditTableColumn:(NSTableColumn *)tableColumn 
              row:(int)row {
  BOOL shouldEdit = YES;
  if ([tableView isEqualTo:sourceTable_]) {
    if ([[tableColumn identifier] isEqualTo:@"name"]) {
      NSArray *sources = [sourcesController_ arrangedObjects];
      StatzSource *source = [sources objectAtIndex:row];
      shouldEdit = [source isNameEditable];
    }
  } else if ([tableView isEqualTo:statusTable_] &&
             [[tableColumn identifier] isEqualTo:@"StatusText"]) {
    [variablesPopup_ setEnabled:YES];
  }
  
  return shouldEdit;
}

- (NSString *)tableView:(NSTableView *)tableView 
         toolTipForCell:(NSCell *)cell 
                   rect:(NSRectPointer)rect 
            tableColumn:(NSTableColumn *)column 
                    row:(int)row 
          mouseLocation:(NSPoint)mouseLocation {
  NSString *toolTip = nil;
  if ([tableView isEqualTo:sourceTable_]) {
    if ([[column identifier] isEqualToString:@"name"]) {
      NSArray *sources = [sourcesController_ arrangedObjects];
      StatzSource *source = [sources objectAtIndex:row];
      if ([source isKindOfClass:[StatzSource class]]) {
        toolTip = [[source currentStatus] toolTip];
      }
    }
  }
  return toolTip;
}

- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row {
  BOOL isGood = YES;
  if ([tableView isEqualTo:sourceTable_]) {
    NSArray *sources = [sourcesController_ arrangedObjects];
    isGood = ![[sources objectAtIndex:row] isKindOfClass:[StatusSettingsTitleItem class]];
  }
  return isGood;
}

- (void)controlTextDidEndEditing:(NSNotification *)aNotification {
  id object = [aNotification object];
  if ([object isEqualTo:statusTable_]) {
    int row = [sourceTable_ selectedRow];
    int column = [sourceTable_ columnWithIdentifier:@"name"];
    [sourceTable_ setNeedsDisplayInRect:[sourceTable_ frameOfCellAtColumn:column row:row]];
    [variablesPopup_ setEnabled:NO];
  } else if ([object isEqualTo:sourceTable_]) {
    int row = [statusTable_ selectedRow];
    if (row == 0) {
      NSArray *statuses = [statusesController_ arrangedObjects];
      if ([statuses count] == 1) {
        Status *status = [[statusesController_ arrangedObjects] objectAtIndex:0];
        if ([[status status] isEqualToString:[Status newStatusString]]) {
          statusToEdit_ = status;
          [NSTimer scheduledTimerWithTimeInterval:0.1 
                                           target:self
                                         selector:@selector(editSelectedStatusIfAppropriateAtTime:) 
                                         userInfo:nil 
                                          repeats:NO];
        }
      }
    }    
  } else if ([object isEqualTo:username_] || [object isEqualTo:password_]) {
    int row = [sourceTable_ selectedRow];
    NSArray *sources = [sourcesController_ arrangedObjects];
    StatzSource *source = [sources objectAtIndex:row];
    [[source plugin] savePreferences];
  }
}

- (void)tableViewSelectionDidChange:(NSNotification *)notification {
  NSTableView *table = [notification object];
  if ([table isEqualTo:sourceTable_]) {
    int row = [table selectedRow];
    NSArray *sources = [sourcesController_ arrangedObjects];
    StatzSource *source = [sources objectAtIndex:row];
    [sourcesController_ setSelectedObjects:[NSArray arrayWithObject:source]];
    [statusTable_ selectRow:[source currentStatusIndex] byExtendingSelection:NO];
    [statePopup_ setMenu:[source stateMenu]];
    [statePopup_ selectItemWithTag:[source state]];
  }
}

- (IBAction)editSelectedSourceName:(id)sender {
  int row = [sourceTable_ selectedRow];
  int column = [sourceTable_ columnWithIdentifier:@"name"];
  [sourceTable_ editColumn:column row:row withEvent:nil select:YES];
}

- (void)editSelectedStatusIfAppropriateAtTime:(NSTimer*)sender {
  if (!statusToEdit_) return;
  int row = [statusTable_ selectedRow];
  Status *status = [[statusesController_ arrangedObjects] objectAtIndex:row];
  if (status == statusToEdit_) {
    int column = [statusTable_ columnWithIdentifier:@"StatusText"];
    [statusTable_ editColumn:column row:row withEvent:nil select:YES];
  }
  statusToEdit_ = nil;
}

- (void)updateVariablesMenu:(NSMenu*)menu {
  // Remove old items
  for (int i = 1, lastItem = [menu numberOfItems]; 
       i < lastItem; ++i) {
    [menu removeItemAtIndex:1];
  }
  
  id responder = [[self window] firstResponder];
  [[menu addItemWithTitle:NSLocalizedString(@"Cut", @"Cut menu item")
                   action:@selector(cut:) 
            keyEquivalent:@"x"] setTarget:responder];
  [[menu addItemWithTitle:NSLocalizedString(@"Copy", @"Copy menu item") 
                   action:@selector(copy:) 
            keyEquivalent:@"c"] setTarget:responder];
  [[menu addItemWithTitle:NSLocalizedString(@"Paste", @"Paste menu item") 
                   action:@selector(paste:) 
            keyEquivalent:@"v"] setTarget:responder];
  [menu addItem:[NSMenuItem separatorItem]];
  [[menu addItemWithTitle:NSLocalizedString(@"Insert", @"Insert menu item")
                  action:nil 
                keyEquivalent:@""] setTarget:self];
  
  // Repopulate
  NSArray *variables = [delegate_ statusVariables];
  NSEnumerator *variableEnum = [variables objectEnumerator];
  StatzSource *source;
  while ((source = [variableEnum nextObject])) {
    NSAttributedString *token = [source nameToken];
    NSMenuItem *item = [menu addItemWithTitle:@"" 
                                       action:@selector(insertVariable:) 
                                keyEquivalent:@""];
    [item setAttributedTitle:token];
    [item setRepresentedObject:source];
    [item setTarget:self];
  }
}

- (void)updateAcccountsMenu:(NSMenu*)menu {
  // Remove old items
  for (int i = 0, lastItem = [menu numberOfItems]; 
       i < lastItem; ++i) {
    [menu removeItemAtIndex:0];
  }
  
  // Repopulate
  NSArray *sinks = [delegate_ statusSinks];
  NSEnumerator *e = [sinks objectEnumerator];
  StatzSink *sink = nil;
  while ((sink = [e nextObject])) {
    if (![sink isEnabled]) {
      NSMenuItem *item = [menu addItemWithTitle:[sink name] 
                                         action:@selector(addAccount:) 
                                  keyEquivalent:@""];
      NSImage *menuImage = [[[sink image] copy] autorelease];
      [menuImage setSize:NSMakeSize(16,16)];
      [item setImage:menuImage];
      [item setRepresentedObject:sink];
      [item setEnabled:YES];
      [item setTarget:self];
    }
  }
}

- (void)updateMasterStateMenu:(NSMenu*)menu {
  NSMenuItem *item = [menu itemWithTag:kStatzStateMixed];
  if (item) {
    [masterStatePopup_ selectItemAtIndex:-1];
    [menu removeItem:item];
  }
}

- (void)updateGearMenu:(NSMenu*)menu {
  NSMenuItem *item = [menu itemWithTag:3];
  NSAssert(item, nil);
  NSArray *sources = [sourcesController_ selectedObjects];
  NSAssert([sources count] == 1, @"");    
  id source = [sources objectAtIndex:0];
  NSString *removeSourceTitle = NSLocalizedString(@"Remove \"%@\"", 
                                                  @"Remove Source Menu Item");
  [item setTitle: [NSString stringWithFormat:removeSourceTitle, 
                       [source name]]];
  item = [menu itemWithTag:4];
  NSString *settingsTitle = NSLocalizedString(@"Show %@ Settings", 
                                              @"Source Settings Menu Item");
  [item setTitle: [NSString stringWithFormat:settingsTitle, 
                       [source name]]];
  [item setState:showAccountSettings_ ? NSOnState : NSOffState];
}

- (void)menuNeedsUpdate:(NSMenu*)menu {
  if ([menu isEqualTo:[variablesPopup_ menu]]) {
    [self updateVariablesMenu:menu];
  } else if ([menu isEqualTo:accountsMenu_]) {
    [self updateAcccountsMenu:menu];
  } else if ([menu isEqualTo:[masterStatePopup_ menu]]) {
    [self updateMasterStateMenu:menu];
  } else if ([menu isEqualTo:gearMenu_]) {
    [self updateGearMenu:menu];
  }
}



- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row {
  if ([[tableColumn identifier] isEqualTo:@"CurrentStatus"]) {
    NSArray *sources = [sourcesController_ selectedObjects];
    StatzSource *source = [sources objectAtIndex:0];
    BOOL value = (unsigned int)row == [source currentStatusIndex];
    return [NSNumber numberWithBool:value];
  } else {
    return nil;
  }
}

- (IBAction)insertVariable:(id)sender {
  StatzSource *source = (StatzSource*)[sender representedObject];
  NSAttributedString *token = [source nameToken];
  NSWindow *window = [self window];
  NSResponder *firstResponder = [window firstResponder];
  if (firstResponder) {
    NSTextView *currentEditor = (NSTextView*)[window fieldEditor:NO forObject:firstResponder];
    [currentEditor insertText:token];
  }
}

- (BOOL)handleKeyDown:(NSEvent*)event {
  BOOL handled = NO;
  NSString *characters = [event characters];
  if ([characters length]) {
    unichar key = [characters characterAtIndex:0];
    NSWindow *window = [self window];
    NSResponder *currentResponder = [window firstResponder];
    if (key == NSRightArrowFunctionKey && sourceTable_ == currentResponder) {
       handled = [window makeFirstResponder:statusTable_];
    } else if (key == NSLeftArrowFunctionKey && statusTable_ == currentResponder) {
      handled = [window makeFirstResponder:sourceTable_];
    }
  }
  return handled;
}

- (IBAction)toggleShowAccountSettings:(id)sender {
  [self setShowAccountSettings:![self showAccountSettings]];
}

- (void)setShowAccountSettings:(BOOL)show {
  showAccountSettings_ = show;
}

- (BOOL)showAccountSettings {
  return showAccountSettings_;
}

- (IBAction)statusSelected:(id)sender {
  int row = [sourceTable_ selectedRow];
  StatzSource *source = [[sourcesController_ selectedObjects] objectAtIndex:0];
  int oldIndex = [source currentStatusIndex];
  int column = [statusTable_ columnWithIdentifier:@"CurrentStatus"];
  NSRect frame = [statusTable_ frameOfCellAtColumn:column row:oldIndex];
  [statusTable_ setNeedsDisplayInRect:frame];
  [source setCurrentStatusIndex:[statusTable_ selectedRow]];
  column = [sourceTable_ columnWithIdentifier:@"name"];
  [sourceTable_ setNeedsDisplayInRect:[sourceTable_ frameOfCellAtColumn:column row:row]];
}

- (IBAction)about:(id)sender {
  [aboutView_ setHidden:NO];
  [gearControl_ setEnabled:NO];
  [addRemoveControl_ setEnabled:NO];
  [sourceTable_ setCellsEnabled:NO];
}

- (IBAction)hideAbout:(id)sender {
  [aboutView_ setHidden:YES];
  [gearControl_ setEnabled:YES];
  [addRemoveControl_ setEnabled:YES];
  [sourceTable_ setCellsEnabled:YES];
  

}

- (void)stateSelected:(id)sender {
  NSEnumerator *sourceEnum = [[sourcesController_ arrangedObjects] objectEnumerator];
  StatzSink *sink;
  unsigned int newState = [sender tag];
  settingMasterState_ = YES;
  while ((sink = [sourceEnum nextObject])) {
    if ([sink isKindOfClass:[StatzSink class]]) {
      [sink setState:newState];
    }
  }
  settingMasterState_ = NO;
  [sourceTable_ reloadData];
  [statePopup_ selectItemWithTag:newState];
}

- (void)statzStateChanged:(NSNotification*)notification {
  if (!settingMasterState_) {
    [sourceTable_ reloadData];
  }
}
@end
